Gitブランチ、Dockerリポジトリ、環境毎のk8sクラスタ 俺のデプロイフローを聞いてほしい
EKSクラスタでアプリケーションを起動させる
これだけでもちょっぴりハードルが高いが、この先にはもっと高いハードルが待ち受けている。そう、
コードを修正してEKSクラスタにデプロイするまでのフローを考える
である。正直適当にやろうと思えばなんとでもなるが、ここを整備しないと不幸な未来が待っているのだ。 ということで今回は、私が考えたデプロイフローとそのフローに到るまでに悩んだポイントを紹介したいと思います。 ※一部机上レベルでの確認になります。
フィードバックお待ちしています。
デプロイフロー
前提
- AWSアカウント:環境毎に分離
- Gitリポジトリ:GitHub
- Dockerレジストリ:ECR
- CI:CodePipeline + CodeBuild
- CD:ArgoCD(後述)
用語
- アプリケーションリポジトリ
- アプリケーションコードを管理するためのリポジトリ
- ArgoCDリポジトリ
- k8sの定義ファイルを管理するためのリポジトリ
アプリケーション(k8sのservice)毎に作成するリソース
- CodePipeline + CodeBuild * 2
- アプリケーションリポジトリのdevelopにmergeされたらビルド
- アプリケーションリポジトリのmasterにmergeされたらビルド
- ECR * 2
- developブランチでビルドされたイメージを格納するためのECR
- masterブランチでビルドされたイメージを格納するためのECR
デプロイフローのイメージはこんな感じです。
開発環境デプロイフロー
- アプリケーションリポジトリのdevブランチへのmergeをtriggerにDockerイメージを作成しECRへPush
- ECRへのPutイベントを検知しArgoCDリポジトリのdevブランチ(の開発環境用にオーバーレイした部分)のイメージタグを更新
- ArgoCDがArgoCDリポジトリのdevブランチの更新を検知して特定のPodを更新
- 開発アカウントでテスト
検証環境デプロイフロー
- ArgoCDリポジトリのdevブランチをstgブランチへmerge(開発環境用にオーバーレイした部分以外に更新がある場合)
- アプリケーションリポジトリのdevブランチをmasterブランチへmerge、mergeをtriggerにDockerイメージを作成しECRへPush
- ECRへのPutイベントを検知しArgoCDリポジトリのstgブランチ(のベースの部分)のイメージタグを更新
- ArgoCDがArgoCDリポジトリのstgブランチの更新を検知して特定のPodを更新
- 検証アカウントでテスト
本番環境デプロイフロー
- ArgoCDリポジトリのstgブランチをmasterブランチへmerge
- ArgoCDがArgoCDリポジトリのmasterブランチの更新を検知して特定のPodを更新
悩んだポイント
この構成に到るまでに悩んだポイントがあります。 それをいくつか紹介します。
どのタイミングでDockerイメージ作るか問題
Q. リリース対象の環境は、開発/検証/本番の3つ。それに対しアプリケーションはどのタイミングでビルド(Dockerイメージを作成)すべきか。
A1. アプリケーションとして環境毎のブランチを作成。環境毎のブランチにコードがマージされたタイミングで環境毎のイメージを作成する。
A2. アプリケーションとして環境毎のブランチは作成しない。masterマージときのみイメージを作成する。なぜなら同じイメージを複数の環境で使い回したいから。
A3. アプリケーションとして開発環境用のイメージを作成するためのブランチ(develop)と、検証/本番環境用のイメージを作成するためのブランチ(master)を作成する。ブランチ(develop)にコードがマージされたタイミングで開発環境用のイメージを、ブランチ(master)にコードがマージされたタイミングで検証/本番環境用のイメージを作成する。
と、いくつか実装案はあったが私のプロジェクトではA3を採用しました。理由は以下の通り。
- A1はわかりやすいが検証/本番のイメージが厳密には違う。できれば同じイメージを利用したい。
- A2は同じイメージの使い回しはできるが開発段階のコードをmasterにマージしなければいけないのが気持ち悪い。
- A3は検証/本番環境で同じイメージが利用できる。また、開発環境用イメージを保存するECRリポジトリと、検証/本番環境用イメージを保存するECRリポジトリとでライフサイクルを変えることができる。
k8s環境差どうやって吸収する問題
Q. 各環境でk8sの設定を分けたい(例えばPod数など)。どこでどのように吸収するべきか。
A. kustomizeを採用。
kustomizeとは以下のようなツールになります。
KustomizeはkubernetesのYAMLファイルをパッケージングするツールです。ベースの構成をもとにSTG/PRDなどの環境ごとに変えたい設定などを上書きすることができます。
kubectl v1.14.0でkustomizeがkubectlに統合されています。
helmという選択肢もありましたが直感的にわかりやすいkustomizeを選択しました。
デプロイツール何使う問題
Q. k8s環境へデプロイするツールは多数存在するが、何を使うべきか。
A. ArgoCDを採用。
ArgoCDとはKubernetesでGitOpsを実現するツールになります。
- EKSでArgo CDのチュートリアルを試してみた
- Kubernetesで作るコンテナベースCI★CDの夕べ / ochacafe#1
- Spinnakerを使ってEKSへの継続的デリバリー環境を構築する
当初はSpinnakerを検討していましたが、やりたいことに対して機能が大きすぎる感があったため、GitOpsを実現できるArgoCDを選択しました。アプリケーションエンジニアにも理解しやすいUI。また、リリース=プルリクエスト承認となるのも理解しやすい。とてもGoodです。
KustomizeとArgoCDの関係は以下の通り。
k8sのYAMLが更新されたときにアプリケーションをビルドしたくない問題
Q. アプリケーションコードとYAML(k8sマニフェスト)はどのように管理すべきだろうか。
A. 更新サイクルが違うため、アプリケーションコードとYAML(k8sマニフェスト)のリポジトリは分ける。
(おまけ)AWSのリソース(ALB、Route53)は何で作る問題
Q. k8sのリソースとして、ALBやRoute53を作成することも可能であるがどこで管理すべきか。
A. k8sでは作成せず、Terraformで作成。
TerraformとはHashiCorp社が提供するインフラ構成管理ツールです。
EKSクラスタのBGデプロイなども考えるとALBやRoute53はEKSクラスタ外で管理した方がわかりやすかろうという判断。実際開発中、操作ミスによりEKSクラスタを何回も壊したため別で管理(Terraform、CDK、CFnなど)する方が楽でした。
さいごに
k8sへのデプロイフローにこれが正解だ!!というものはおそらくないと思います。なので自分たちのプロダクトに合わせ最適なものを選定する必要があると感じました。どなたかの参考になれば幸いです。